﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using l1cs.server.model.Instance;
using l1cs.server.command;
using l1cs.server.templates;
using l1cs.server.serverpackets;
using System.Reflection;
using l1cs.server.model;
using l1cs.server.datatables;
using l1cs.server.clientpackets;
using l1cs.server.model.skill;
using l1cs.server.model.map;
using l1cs.server.utils;
using l1cs.server.model.trap;
using System.Collections;

namespace l1cs.server
{
    public class GMCommands
    {
        private static Logger _log = Logger.getLogger( typeof( GMCommands ).FullName );

        private static GMCommands _instance;

        private GMCommands() { }

        public static GMCommands getInstance()
        {
            if ( _instance == null )
            {
                _instance = new GMCommands();
            }
            return _instance;
        }

        private String complementClassName( String className )
        {
            // .が含まれていればフルパスと見なしてそのまま返す
            if ( className.Contains( "." ) )
            {
                return className;
            }

            // デフォルトパッケージ名を補完
            return "l1j.server.server.command.executor." + className;
        }

        private bool executeDatabaseCommand( L1PcInstance pc, String name, String arg )
        {
            L1Command command = L1Commands.get( name );
            if ( command == null )
            {
                return false;
            }
            if ( pc.getAccessLevel() < command.getLevel() )
            {
                pc.sendPackets( new S_ServerMessage( 74, "コマンド" + name ) ); // \f1%0は使用できません。
                return true;
            }

            switch ( command.getExecutorClassName() )
            {
                case "L1AccountBanKick": L1AccountBanKick( pc, name, arg ); break;
                case "L1Action": L1Action( pc, name, arg ); break;
                case "L1AddSkill": L1AddSkill( pc, name, arg ); break;
                case "L1Adena": L1Adena( pc, name, arg ); break;
                case "L1AllBuff": L1AllBuff( pc, name, arg ); break;
                case "L1BanIp": L1BanIp( pc, name, arg ); break;
                case "L1Buff": L1Buff( pc, name, arg ); break;
                case "L1CastGfx": L1CastGfx( pc, name, arg ); break;
                case "L1ChangeWeather": L1ChangeWeather( pc, name, arg ); break;
                case "L1Chat": L1Chat( pc, name, arg ); break;
                case "L1ChatNG": L1ChatNG( pc, name, arg ); break;
                case "L1CommandHelp": L1CommandHelp( pc, name, arg ); break;
                case "L1CreateItem": L1CreateItem( pc, name, arg ); break;
                case "L1CreateItemSet": L1CreateItemSet( pc, name, arg ); break;
                case "L1DeleteGroundItem": L1DeleteGroundItem( pc, name, arg ); break;
                case "L1Describe": L1Describe( pc, name, arg ); break;
                case "L1Favorite": L1Favorite( pc, name, arg ); break;
                case "L1FindInvis": L1FindInvis( pc, name, arg ); break;
                case "L1GfxId": L1GfxId( pc, name, arg ); break;
                case "L1GM": L1GM( pc, name, arg ); break;
                case "L1GMRoom": L1GMRoom( pc, name, arg ); break;
                case "L1HomeTown": L1HomeTown( pc, name, arg ); break;
                case "L1HpBar": L1HpBar( pc, name, arg ); break;
                case "L1InsertSpawn": L1InsertSpawn( pc, name, arg ); break;
                case "L1InvGfxId": L1InvGfxId( pc, name, arg ); break;
                case "L1Invisible": L1Invisible( pc, name, arg ); break;
                case "L1Kick": L1Kick( pc, name, arg ); break;
                case "L1Kill": L1Kill( pc, name, arg ); break;
                case "L1Level": L1Level( pc, name, arg ); break;
                case "L1LevelPresent": L1LevelPresent( pc, name, arg ); break;
                case "L1Loc": L1Loc( pc, name, arg ); break;
                case "L1Move": L1Move( pc, name, arg ); break;
                case "L1PartyRecall": L1PartyRecall( pc, name, arg ); break;
                case "L1Patrol": L1Patrol( pc, name, arg ); break;
                case "L1Poly": L1Poly( pc, name, arg ); break;
                case "L1PowerKick": L1PowerKick( pc, name, arg ); break;
                case "L1Present": L1Present( pc, name, arg ); break;
                case "L1Recall": L1Recall( pc, name, arg ); break;
                case "L1ReloadTrap": L1ReloadTrap( pc, name, arg ); break;
                case "L1ResetTrap": L1ResetTrap( pc, name, arg ); break;
                case "L1Ress": L1Ress( pc, name, arg ); break;
                case "L1ShowTrap": L1ShowTrap( pc, name, arg ); break;
                case "L1Shutdown": L1Shutdown( pc, name, arg ); break;
                case "L1SKick": L1SKick( pc, name, arg ); break;
                case "L1SpawnCmd": L1SpawnCmd( pc, name, arg ); break;
                case "L1Speed": L1Speed( pc, name, arg ); break;
                case "L1Status": L1Status( pc, name, arg ); break;
                case "L1Summon": L1Summon( pc, name, arg ); break;
                case "L1Tile": L1Tile( pc, name, arg ); break;
                case "L1ToPC": L1ToPC( pc, name, arg ); break;
                case "L1ToSpawn": L1ToSpawn( pc, name, arg ); break;
                case "L1Visible": L1Visible( pc, name, arg ); break;
                case "L1Who": L1Who( pc, name, arg ); break;
                case "L1Echo": L1Echo( pc, name, arg ); break;
            }
            _log.info( pc.getName() + "が." + name + " " + arg + "コマンドを使用しました。" );
            return true;
        }

        public void handleCommands( L1PcInstance gm, String cmdLine )
        {
            StringTokenizer token = new StringTokenizer( cmdLine );
            // 最初の空白までがコマンド、それ以降は空白を区切りとしたパラメータとして扱う
            String cmd = token.nextToken();
            String param = "";
            int i = 0;
            while ( token.hasMoreTokens() )
            {
                if ( i++ == 0 ) continue;
                param = new StringBuilder( param ).Append( token.nextToken() ).Append( ' ' ).ToString();
            }
            param = param.Trim();

            // データベース化されたコマンド
            if ( executeDatabaseCommand( gm, cmd, param ) )
            {
                if ( string.Compare( cmd, "r", true ) != 0 )
                {
                    _lastCommands[gm.getId()] = cmdLine;
                }
                return;
            }
            if ( string.Compare( cmd, "r", true ) == 0 )
            {
                if ( !_lastCommands.ContainsKey( gm.getId() ) )
                {
                    gm.sendPackets( new S_ServerMessage( 74, "コマンド" + cmd ) ); // \f1%0は使用できません。
                    return;
                }
                redo( gm, param );
                return;
            }
            gm.sendPackets( new S_SystemMessage( "コマンド " + cmd + " は存在しません。" ) );
        }

        private static Dictionary<int, String> _lastCommands = new Dictionary<int, String>();

        private void redo( L1PcInstance pc, String arg )
        {
            try
            {
                String lastCmd = _lastCommands[pc.getId()];
                if ( arg.Length == 0 )
                {
                    pc.sendPackets( new S_SystemMessage( "コマンド " + lastCmd + " を再実行します" ) );
                    handleCommands( pc, lastCmd );
                }
                else
                {
                    // 引数を変えて実行
                    StringTokenizer token = new StringTokenizer( lastCmd );
                    String cmd = token.nextToken() + " " + arg;
                    pc.sendPackets( new S_SystemMessage( "コマンド " + cmd + " を実行します。" ) );
                    handleCommands( pc, cmd );
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( ".r コマンドエラー" ) );
            }
        }

        private void L1AccountBanKick( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                L1PcInstance target = L1World.getInstance().getPlayer( arg );

                if ( target != null )
                {
                    // アカウントをBANする
                    Account.ban( target.getAccountName() );
                    pc.sendPackets( new S_SystemMessage( target.getName() + "さんをキックしました。" ) );
                    target.sendPackets( new S_Disconnect() );
                }
                else
                {
                    pc.sendPackets( new S_SystemMessage(
                            "そのような名前のキャラクターはワールド内には存在しません。" ) );
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " キャラクター名 と入力して下さい。" ) );
            }
        }

        private void L1Action( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer st = new StringTokenizer( arg );
                int actId = Convert.ToInt32( st.nextToken() );
                pc.sendPackets( new S_DoActionGFX( pc.getId(), actId ) );
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " actid と入力して下さい。" ) );
            }
        }

        private void L1AddSkill( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                int cnt = 0; // ループカウンタ
                String skill_name = ""; // スキル名
                int skill_id = 0; // スキルID

                int object_id = pc.getId(); // キャラクタのobjectidを取得
                pc.sendPackets( new S_SkillSound( object_id, 227 ) ); // 魔法習得の効果音を鳴らす
                pc.broadcastPacket( new S_SkillSound( object_id, 227 ) );

                if ( pc.isCrown() )
                {
                    pc.sendPackets( new S_AddSkill( 255, 255, 0, 0, 0, 0, 0, 0, 0, 0,
                            0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) );
                    for ( cnt = 1; cnt <= 16; cnt++ ) // LV1~2魔法
                    {
                        L1Skills l1skills = SkillsTable.getInstance().getTemplate(
                                cnt ); // スキル情報を取得
                        skill_name = l1skills.getName();
                        skill_id = l1skills.getSkillId();
                        SkillsTable.getInstance().spellMastery( object_id, skill_id,
                                skill_name, 0, 0 ); // DBに登録
                    }
                    for ( cnt = 113; cnt <= 120; cnt++ ) // プリ魔法
                    {
                        L1Skills l1skills = SkillsTable.getInstance().getTemplate(
                                cnt ); // スキル情報を取得
                        skill_name = l1skills.getName();
                        skill_id = l1skills.getSkillId();
                        SkillsTable.getInstance().spellMastery( object_id, skill_id,
                                skill_name, 0, 0 ); // DBに登録
                    }
                }
                else if ( pc.isKnight() )
                {
                    pc.sendPackets( new S_AddSkill( 255, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                            192, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) );
                    for ( cnt = 1; cnt <= 8; cnt++ ) // LV1魔法
                    {
                        L1Skills l1skills = SkillsTable.getInstance().getTemplate(
                                cnt ); // スキル情報を取得
                        skill_name = l1skills.getName();
                        skill_id = l1skills.getSkillId();
                        SkillsTable.getInstance().spellMastery( object_id, skill_id,
                                skill_name, 0, 0 ); // DBに登録
                    }
                    for ( cnt = 87; cnt <= 91; cnt++ ) // ナイト魔法
                    {
                        L1Skills l1skills = SkillsTable.getInstance().getTemplate(
                                cnt ); // スキル情報を取得
                        skill_name = l1skills.getName();
                        skill_id = l1skills.getSkillId();
                        SkillsTable.getInstance().spellMastery( object_id, skill_id,
                                skill_name, 0, 0 ); // DBに登録
                    }
                }
                else if ( pc.isElf() )
                {
                    pc.sendPackets( new S_AddSkill( 255, 255, 127, 255, 255, 255, 0,
                            0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 3, 255, 255, 255, 255,
                            0, 0, 0, 0, 0, 0 ) );
                    for ( cnt = 1; cnt <= 48; cnt++ ) // LV1~6魔法
                    {
                        L1Skills l1skills = SkillsTable.getInstance().getTemplate(
                                cnt ); // スキル情報を取得
                        skill_name = l1skills.getName();
                        skill_id = l1skills.getSkillId();
                        SkillsTable.getInstance().spellMastery( object_id, skill_id,
                                skill_name, 0, 0 ); // DBに登録
                    }
                    for ( cnt = 129; cnt <= 176; cnt++ ) // エルフ魔法
                    {
                        L1Skills l1skills = SkillsTable.getInstance().getTemplate(
                                cnt ); // スキル情報を取得
                        skill_name = l1skills.getName();
                        skill_id = l1skills.getSkillId();
                        SkillsTable.getInstance().spellMastery( object_id, skill_id,
                                skill_name, 0, 0 ); // DBに登録
                    }
                }
                else if ( pc.isWizard() )
                {
                    pc.sendPackets( new S_AddSkill( 255, 255, 127, 255, 255, 255,
                            255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                            0, 0, 0, 0, 0, 0 ) );
                    for ( cnt = 1; cnt <= 80; cnt++ ) // LV1~10魔法
                    {
                        L1Skills l1skills = SkillsTable.getInstance().getTemplate(
                                cnt ); // スキル情報を取得
                        skill_name = l1skills.getName();
                        skill_id = l1skills.getSkillId();
                        SkillsTable.getInstance().spellMastery( object_id, skill_id,
                                skill_name, 0, 0 ); // DBに登録
                    }
                }
                else if ( pc.isDarkelf() )
                {
                    pc.sendPackets( new S_AddSkill( 255, 255, 0, 0, 0, 0, 0, 0, 0, 0,
                            0, 0, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) );
                    for ( cnt = 1; cnt <= 16; cnt++ ) // LV1~2魔法
                    {
                        L1Skills l1skills = SkillsTable.getInstance().getTemplate(
                                cnt ); // スキル情報を取得
                        skill_name = l1skills.getName();
                        skill_id = l1skills.getSkillId();
                        SkillsTable.getInstance().spellMastery( object_id, skill_id,
                                skill_name, 0, 0 ); // DBに登録
                    }
                    for ( cnt = 97; cnt <= 111; cnt++ ) // DE魔法
                    {
                        L1Skills l1skills = SkillsTable.getInstance().getTemplate(
                                cnt ); // スキル情報を取得
                        skill_name = l1skills.getName();
                        skill_id = l1skills.getSkillId();
                        SkillsTable.getInstance().spellMastery( object_id, skill_id,
                                skill_name, 0, 0 ); // DBに登録
                    }
                }
                else if ( pc.isDragonKnight() )
                {
                    pc.sendPackets( new S_AddSkill( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 7, 0, 0, 0 ) );
                    for ( cnt = 181; cnt <= 195; cnt++ ) // ドラゴンナイト秘技
                    {
                        L1Skills l1skills = SkillsTable.getInstance().getTemplate(
                                cnt ); // スキル情報を取得
                        skill_name = l1skills.getName();
                        skill_id = l1skills.getSkillId();
                        SkillsTable.getInstance().spellMastery( object_id, skill_id,
                                skill_name, 0, 0 ); // DBに登録
                    }
                }
                else if ( pc.isIllusionist() )
                {
                    pc.sendPackets( new S_AddSkill( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 15 ) );
                    for ( cnt = 201; cnt <= 220; cnt++ ) // イリュージョニスト魔法
                    {
                        L1Skills l1skills = SkillsTable.getInstance().getTemplate(
                                cnt ); // スキル情報を取得
                        skill_name = l1skills.getName();
                        skill_id = l1skills.getSkillId();
                        SkillsTable.getInstance().spellMastery( object_id, skill_id,
                                skill_name, 0, 0 ); // DBに登録
                    }
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " コマンドエラー" ) );
            }
        }

        private void L1Adena( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer stringtokenizer = new StringTokenizer( arg );
                int count = Convert.ToInt32( stringtokenizer.nextToken() );

                L1ItemInstance adena = pc.getInventory().storeItem( L1ItemId.ADENA,
                        count );
                if ( adena != null )
                {
                    pc.sendPackets( new S_SystemMessage( ( new StringBuilder() )
                            .Append( count ).Append( "アデナを生成しました。" ).ToString() ) );
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( ( new StringBuilder() ).Append(
                        ".adena アデナ数 と入力して下さい。" ).ToString() ) );
            }
        }

        private void L1AllBuff( L1PcInstance pc, String cmdName, String arg )
        {
            int[] allBuffSkill = { 
                L1SkillId.LIGHT, L1SkillId.DECREASE_WEIGHT, L1SkillId.PHYSICAL_ENCHANT_DEX,
				L1SkillId.MEDITATION, L1SkillId.PHYSICAL_ENCHANT_STR, L1SkillId.BLESS_WEAPON, 
                L1SkillId.BERSERKERS, L1SkillId.IMMUNE_TO_HARM, L1SkillId.ADVANCE_SPIRIT, L1SkillId.REDUCTION_ARMOR, L1SkillId.BOUNCE_ATTACK,
				L1SkillId.SOLID_CARRIAGE, L1SkillId.ENCHANT_VENOM, L1SkillId.BURNING_SPIRIT, L1SkillId.VENOM_RESIST,
				L1SkillId.DOUBLE_BRAKE, L1SkillId.UNCANNY_DODGE, L1SkillId.DRESS_EVASION, L1SkillId.GLOWING_AURA,
				L1SkillId.BRAVE_AURA, L1SkillId.RESIST_MAGIC, L1SkillId.CLEAR_MIND, L1SkillId.ELEMENTAL_PROTECTION,
				L1SkillId.AQUA_PROTECTER, L1SkillId.BURNING_WEAPON, L1SkillId.IRON_SKIN, L1SkillId.EXOTIC_VITALIZE,
				L1SkillId.WATER_LIFE, L1SkillId.ELEMENTAL_FIRE, L1SkillId.SOUL_OF_FLAME, L1SkillId.ADDITIONAL_FIRE };
            try
            {
                StringTokenizer st = new StringTokenizer( arg );
                String name = st.nextToken();
                L1PcInstance target = L1World.getInstance().getPlayer( name );
                if ( target == null )
                {
                    pc.sendPackets( new S_ServerMessage( 73, name ) ); // \f1%0はゲームをしていません。
                    return;
                }

                L1BuffUtil.haste( target, 3600 * 1000 );
                L1BuffUtil.brave( target, 3600 * 1000 );
                L1PolyMorph.doPoly( target, 5641, 7200, L1PolyMorph.MORPH_BY_GM );
                for ( int i = 0; i < allBuffSkill.Length; i++ )
                {
                    L1Skills skill = SkillsTable.getInstance().getTemplate(
                            allBuffSkill[i] );
                    new L1SkillUse().handleCommands( target, allBuffSkill[i], target
                            .getId(), target.getX(), target.getY(), null, skill
                                    .getBuffDuration() * 1000, L1SkillUse.TYPE_GMBUFF );
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( ".allBuff キャラクター名 と入力して下さい。" ) );
            }
        }

        private void L1BanIp( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer stringtokenizer = new StringTokenizer( arg );
                // IPを指定
                String s1 = stringtokenizer.nextToken();

                // add/delを指定(しなくてもOK)
                String s2 = null;
                try
                {
                    s2 = stringtokenizer.nextToken();
                }
                catch ( Exception e )
                {
                    _log.log( Level.SEVERE, e.StackTrace );
                    _log.info( e.Message + "\n" + e.StackTrace );
                }

                IpTable iptable = IpTable.getInstance();
                bool isBanned = iptable.isBannedIp( s1 );

                foreach ( L1PcInstance tg in L1World.getInstance().getAllPlayers() )
                {
                    if ( s1.Equals( tg.getNetConnection().getIp() ) )
                    {
                        String msg = new StringBuilder().Append( "IP:" ).Append( s1 )
                                .Append( " で接続中のプレイヤー:" ).Append( tg.getName() )
                                .ToString();
                        pc.sendPackets( new S_SystemMessage( msg ) );
                    }
                }

                if ( "add".Equals( s2 ) && !isBanned )
                {
                    iptable.banIp( s1 ); // BANリストへIPを加える
                    String msg = new StringBuilder().Append( "IP:" ).Append( s1 )
                            .Append( " をBAN IPに登録しました。" ).ToString();
                    pc.sendPackets( new S_SystemMessage( msg ) );
                }
                else if ( "del".Equals( s2 ) && isBanned )
                {
                    if ( iptable.liftBanIp( s1 ) )
                    { // BANリストからIPを削除する
                        String msg = new StringBuilder().Append( "IP:" ).Append( s1 )
                                .Append( " をBAN IPから削除しました。" ).ToString();
                        pc.sendPackets( new S_SystemMessage( msg ) );
                    }
                }
                else
                {
                    // BANの確認
                    if ( isBanned )
                    {
                        String msg = new StringBuilder().Append( "IP:" ).Append( s1 )
                                .Append( " はBAN IPに登録されています。" ).ToString();
                        pc.sendPackets( new S_SystemMessage( msg ) );
                    }
                    else
                    {
                        String msg = new StringBuilder().Append( "IP:" ).Append( s1 )
                                .Append( " はBAN IPに登録されていません。" ).ToString();
                        pc.sendPackets( new S_SystemMessage( msg ) );
                    }
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " IP [ add | del ]と入力して下さい。" ) );
            }
        }

        private void L1Buff( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer tok = new StringTokenizer( arg );
                List<L1PcInstance> players = null;
                String s = tok.nextToken();
                if ( s.Equals( "me" ) )
                {
                    players = new List<L1PcInstance>();
                    players.Add( pc );
                    s = tok.nextToken();
                }
                else if ( s.Equals( "all" ) )
                {
                    foreach ( L1PcInstance lpi in L1World.getInstance().getAllPlayers() )
                    {
                        players.Add( lpi );
                    }
                    s = tok.nextToken();
                }
                else
                {
                    players = L1World.getInstance().getVisiblePlayer( pc );
                }

                int skillId = Convert.ToInt32( s );
                int time = 0;
                if ( tok.hasMoreTokens() )
                {
                    {
                        time = Convert.ToInt32( tok.nextToken() );
                    }

                    L1Skills skill = SkillsTable.getInstance().getTemplate( skillId );

                    if ( skill.getTarget().Equals( "buff" ) )
                    {
                        foreach ( L1PcInstance tg in players )
                        {
                            new L1SkillUse().handleCommands( pc, skillId, tg.getId(), tg
                                    .getX(), tg.getY(), null, time, L1SkillUse.TYPE_SPELLSC );
                        }
                    }
                    else if ( skill.getTarget().Equals( "none" ) )
                    {
                        foreach ( L1PcInstance tg in players )
                        {
                            new L1SkillUse().handleCommands( tg, skillId, tg.getId(), tg
                                    .getX(), tg.getY(), null, time, L1SkillUse.TYPE_GMBUFF );
                        }
                    }
                    else
                    {
                        pc.sendPackets( new S_SystemMessage( "buff系のスキルではありません。" ) );
                    }
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " [all|me] skillId time と入力して下さい。" ) );
            }
        }

        private void L1CastGfx( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer stringtokenizer = new StringTokenizer( arg );
                int sprid = Convert.ToInt32( stringtokenizer.nextToken() );

                pc.sendPackets( new S_SkillSound( pc.getId(), sprid ) );
                pc.broadcastPacket( new S_SkillSound( pc.getId(), sprid ) );
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " castgfxid と入力して下さい。" ) );
            }
        }

        private void L1ChangeWeather( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer stringtokenizer = new StringTokenizer( arg );
                int weather = Convert.ToInt32( stringtokenizer.nextToken() );
                L1World.getInstance().setWeather( weather );
                L1World.getInstance().broadcastPacketToAll( new S_Weather( weather ) );
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " 0～3、16～19 と入力して下さい。" ) );
            }
        }

        private void L1Chat( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer st = new StringTokenizer( arg );
                if ( st.hasMoreTokens() )
                {
                    String flag = st.nextToken();
                    String msg;
                    if ( string.Compare( flag, "on", true ) == 0 )
                    {
                        L1World.getInstance().set_worldChatElabled( true );
                        msg = "ワールドチャットを有効にしました。";
                    }
                    else if ( string.Compare( flag, "off", true ) == 0 )
                    {
                        L1World.getInstance().set_worldChatElabled( false );
                        msg = "ワールドチャットを停止しました。";
                    }
                    else
                    {
                        throw new Exception();
                    }
                    pc.sendPackets( new S_SystemMessage( msg ) );
                }
                else
                {
                    String msg;
                    if ( L1World.getInstance().isWorldChatElabled() )
                    {
                        msg = "現在ワールドチャットは有効です。.chat off で停止できます。";
                    }
                    else
                    {
                        msg = "現在ワールドチャットは停止しています。.chat on で有効にできます。";
                    }
                    pc.sendPackets( new S_SystemMessage( msg ) );
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " [on|off]" ) );
            }
        }

        private void L1ChatNG( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer st = new StringTokenizer( arg );
                String name = st.nextToken();
                int time = Convert.ToInt32( st.nextToken() );

                L1PcInstance tg = L1World.getInstance().getPlayer( name );

                if ( tg != null )
                {
                    tg.setSkillEffect( L1SkillId.STATUS_CHAT_PROHIBITED, time * 60 * 1000 );
                    tg.sendPackets( new S_SkillIconGFX( 36, time * 60 ) );
                    tg.sendPackets( new S_ServerMessage( 286, time.ToString() ) ); // \f3ゲームに適合しない行動であるため、今後%0分間チャットを禁じます。
                    pc.sendPackets( new S_ServerMessage( 287, name ) ); // %0のチャットを禁じました。
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " キャラクター名 時間（分） と入力して下さい。" ) );
            }
        }

        private void L1CommandHelp( L1PcInstance pc, String cmdName, String arg )
        {
            string with = ", ";
            List<L1Command> list = L1Commands.availableCommandList( pc.getAccessLevel() );
            StringBuilder result = new StringBuilder();
            foreach ( L1Command cmd in list )
            {
                if ( result.Length > 0 )
                {
                    result.Append( with );
                }
                result.Append( cmd.getName() );
            }
            pc.sendPackets( new S_SystemMessage( result.ToString() ) );
        }

        private void L1CreateItem( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer st = new StringTokenizer( arg );
                String nameid = st.nextToken();
                int count = 1;
                if ( st.hasMoreTokens() )
                {
                    count = Convert.ToInt32( st.nextToken() );
                }
                int enchant = 0;
                if ( st.hasMoreTokens() )
                {
                    enchant = Convert.ToInt32( st.nextToken() );
                }
                int isId = 0;
                if ( st.hasMoreTokens() )
                {
                    isId = Convert.ToInt32( st.nextToken() );
                }
                int itemid = 0;
                try
                {
                    itemid = Convert.ToInt32( nameid );
                }
                catch ( Exception e )
                {
                    itemid = ItemTable.getInstance().findItemIdByNameWithoutSpace(
                            nameid );
                    if ( itemid == 0 )
                    {
                        pc.sendPackets( new S_SystemMessage( "該当アイテムが見つかりません。" ) );
                        return;
                    }
                }
                L1Item temp = ItemTable.getInstance().getTemplate( itemid );
                if ( temp != null )
                {
                    if ( temp.isStackable() )
                    {
                        L1ItemInstance item = ItemTable.getInstance().createItem(
                                itemid );
                        item.setEnchantLevel( 0 );
                        item.setCount( count );
                        if ( isId == 1 )
                        {
                            item.setIdentified( true );
                        }
                        if ( pc.getInventory().checkAddItem( item, count ) == L1Inventory.OK )
                        {
                            pc.getInventory().storeItem( item );
                            pc.sendPackets( new S_ServerMessage( 403, // %0を手に入れました。
                                    item.getLogName() + "(ID:" + itemid + ")" ) );
                        }
                    }
                    else
                    {
                        L1ItemInstance item = null;
                        int createCount;
                        for ( createCount = 0; createCount < count; createCount++ )
                        {
                            item = ItemTable.getInstance().createItem( itemid );
                            item.setEnchantLevel( enchant );
                            if ( isId == 1 )
                            {
                                item.setIdentified( true );
                            }
                            if ( pc.getInventory().checkAddItem( item, 1 ) == L1Inventory.OK )
                            {
                                pc.getInventory().storeItem( item );
                            }
                            else
                            {
                                break;
                            }
                        }
                        if ( createCount > 0 )
                        {
                            pc.sendPackets( new S_ServerMessage( 403, // %0を手に入れました。
                                    item.getLogName() + "(ID:" + itemid + ")" ) );
                        }
                    }
                }
                else
                {
                    pc.sendPackets( new S_SystemMessage( "指定IDのアイテムは存在しません" ) );
                }
            }
            catch ( Exception e )
            {
                pc.sendPackets( new S_SystemMessage(
                        ".item itemid|name [個数] [エンチャント数] [鑑定状態] と入力して下さい。" ) );
            }
        }

        private void L1CreateItemSet( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                String name = new StringTokenizer( arg ).nextToken();
                List<L1ItemSetItem> list = GMCommandsConfig.ITEM_SETS[name];
                if ( list == null )
                {
                    pc.sendPackets( new S_SystemMessage( name + " 未定義のセットです" ) );
                    return;
                }
                foreach ( L1ItemSetItem item in list )
                {
                    L1Item temp = ItemTable.getInstance().getTemplate( item.getId() );
                    if ( !temp.isStackable() && 0 != item.getEnchant() )
                    {
                        for ( int i = 0; i < item.getAmount(); i++ )
                        {
                            L1ItemInstance inst = ItemTable.getInstance()
                                    .createItem( item.getId() );
                            inst.setEnchantLevel( item.getEnchant() );
                            pc.getInventory().storeItem( inst );
                        }
                    }
                    else
                    {
                        pc.getInventory().storeItem( item.getId(), item.getAmount() );
                    }
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( ".itemset セット名 と入力してください。" ) );
            }
        }

        private void L1DeleteGroundItem( L1PcInstance pc, String cmdName, String arg )
        {
            foreach ( L1Object l1object in L1World.getInstance().getObject() )
            {
                if ( l1object is L1ItemInstance )
                {
                    L1ItemInstance l1iteminstance = (L1ItemInstance)l1object;
                    if ( l1iteminstance.getX() == 0 && l1iteminstance.getY() == 0 )
                    { // 地面上のアイテムではなく、誰かの所有物
                        continue;
                    }

                    List<L1PcInstance> players = L1World.getInstance()
                            .getVisiblePlayer( l1iteminstance, 0 );
                    if ( 0 == players.Count )
                    {
                        L1Inventory groundInventory = L1World.getInstance()
                                .getInventory( l1iteminstance.getX(),
                                        l1iteminstance.getY(),
                                        l1iteminstance.getMapId() );
                        int itemId = l1iteminstance.getItem().getItemId();
                        if ( itemId == 40314 || itemId == 40316 )
                        { // ペットのアミュレット
                            PetTable.getInstance()
                                    .deletePet( l1iteminstance.getId() );
                        }
                        else if ( itemId >= 49016 && itemId <= 49025 )
                        { // 便箋
                            LetterTable.deleteLetter( l1iteminstance.getId() );
                        }
                        else if ( itemId >= 41383 && itemId <= 41400 )
                        { // 家具
                            if ( l1object is L1FurnitureInstance )
                            {
                                L1FurnitureInstance furniture = (L1FurnitureInstance)l1object;
                                if ( furniture.getItemObjId() == l1iteminstance
                                        .getId() )
                                { // 既に引き出している家具
                                    FurnitureSpawnTable.getInstance()
                                            .deleteFurniture( furniture );
                                }
                            }
                        }
                        groundInventory.deleteItem( l1iteminstance );
                        L1World.getInstance().removeVisibleObject( l1iteminstance );
                        L1World.getInstance().removeObject( l1iteminstance );
                    }
                }
            }
            L1World.getInstance().broadcastServerMessage(
                    "ワールドマップ上のアイテムがGMにより削除されました。" );
        }

        private void L1Describe( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringBuilder msg = new StringBuilder();
                pc.sendPackets( new S_SystemMessage( "-- describe: " + pc.getName()
                        + " --" ) );
                int hpr = pc.getHpr() + pc.getInventory().hpRegenPerTick();
                int mpr = pc.getMpr() + pc.getInventory().mpRegenPerTick();
                msg.Append( "Dmg: +" + pc.getDmgup() + " / " );
                msg.Append( "Hit: +" + pc.getHitup() + " / " );
                msg.Append( "MR: " + pc.getMr() + " / " );
                msg.Append( "HPR: " + hpr + " / " );
                msg.Append( "MPR: " + mpr + " / " );
                msg.Append( "Karma: " + pc.getKarma() + " / " );
                msg.Append( "Item: " + pc.getInventory().getSize() + " / " );
                pc.sendPackets( new S_SystemMessage( msg.ToString() ) );
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " コマンドエラー" ) );
            }
        }

        private static Dictionary<int, String> _faviCom = new Dictionary<int, String>();
        private void L1Favorite( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                if ( !_faviCom.ContainsKey( pc.getId() ) )
                {
                    _faviCom.Add( pc.getId(), "" );
                }
                String faviCom = _faviCom[pc.getId()];
                if ( arg.StartsWith( "set" ) )
                {
                    // コマンドの登録
                    StringTokenizer st = new StringTokenizer( arg );
                    st.nextToken();
                    if ( !st.hasMoreTokens() )
                    {
                        pc.sendPackets( new S_SystemMessage( "コマンドが空です。" ) );
                        return;
                    }
                    StringBuilder cmd = new StringBuilder();
                    String temp = st.nextToken(); // コマンドタイプ
                    if ( string.Compare( temp, cmdName, true ) == 0 )
                    {
                        pc.sendPackets( new S_SystemMessage( cmdName + " 自身は登録できません。" ) );
                        return;
                    }
                    cmd.Append( temp + " " );
                    while ( st.hasMoreTokens() )
                    {
                        cmd.Append( st.nextToken() + " " );
                    }
                    faviCom = cmd.ToString().Trim();
                    _faviCom.Add( pc.getId(), faviCom );
                    pc.sendPackets( new S_SystemMessage( faviCom + " を登録しました。" ) );
                }
                else if ( arg.StartsWith( "show" ) )
                {
                    pc.sendPackets( new S_SystemMessage( "現在の登録コマンド: " + faviCom ) );
                }
                else if ( faviCom.Length == 0 )
                {
                    pc.sendPackets( new S_SystemMessage( "登録しているコマンドがありません。" ) );
                }
                else
                {
                    StringBuilder cmd = new StringBuilder();
                    StringTokenizer st = new StringTokenizer( arg );
                    StringTokenizer st2 = new StringTokenizer( faviCom );
                    int i;
                    while ( st2.hasMoreTokens() )
                    {
                        String temp = st2.nextToken();
                        if ( temp.StartsWith( "%" ) )
                        {
                            cmd.Append( st.nextToken() + " " );
                        }
                        else
                        {
                            cmd.Append( temp + " " );
                        }
                    }
                    while ( st.hasMoreTokens() )
                    {
                        cmd.Append( st.nextToken() + " " );
                    }
                    pc.sendPackets( new S_SystemMessage( cmd + " を実行します。" ) );
                    GMCommands.getInstance().handleCommands( pc, cmd.ToString() );
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " set コマンド名 " + "| "
                        + cmdName + " show | " + cmdName + " [引数] と入力してください。" ) );
            }
        }

        private void L1FindInvis( L1PcInstance pc, String cmdName, String arg )
        {
            if ( string.Compare( arg, "on", true ) == 0 )
            {
                pc.setSkillEffect( L1SkillId.GMSTATUS_FINDINVIS, 0 );
                pc.removeAllKnownObjects();
                pc.updateObject();
            }
            else if ( string.Compare( arg, "off", true ) == 0 )
            {
                pc.removeSkillEffect( L1SkillId.GMSTATUS_FINDINVIS );
                foreach ( L1PcInstance visible in L1World.getInstance().getVisiblePlayer( pc ) )
                {
                    if ( visible.isInvisble() )
                    {
                        pc.sendPackets( new S_RemoveObject( visible ) );
                    }
                }
            }
            else
            {
                pc.sendPackets( new S_SystemMessage( cmdName + " on|off と入力してください。" ) );
            }
        }

        private void L1GfxId( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer st = new StringTokenizer( arg );
                int gfxid = Convert.ToInt32( st.nextToken() );
                int count = Convert.ToInt32( st.nextToken() );
                for ( int i = 0; i < count; i++ )
                {
                    L1Npc l1npc = NpcTable.getInstance().getTemplate( 45001 );
                    if ( l1npc != null )
                    {
                        String s = l1npc.getImpl();
                        Type t = Type.GetType( "l1j.server.server.model.Instance." + s + "Instance" );
                        L1NpcInstance npc = (L1NpcInstance)t.InvokeMember( null,
                                                BindingFlags.CreateInstance,
                                                null, null,
                                                new object[] { l1npc } );
                        npc.setId( IdFactory.getInstance().nextId() );
                        npc.setGfxId( gfxid + i );
                        npc.setTempCharGfx( 0 );
                        npc.setNameId( "" );
                        npc.setMap( pc.getMapId() );
                        npc.setX( pc.getX() + i * 2 );
                        npc.setY( pc.getY() + i * 2 );
                        npc.setHomeX( npc.getX() );
                        npc.setHomeY( npc.getY() );
                        npc.setHeading( 4 );

                        L1World.getInstance().storeObject( npc );
                        L1World.getInstance().addVisibleObject( npc );
                    }
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " id 出現させる数 と入力して下さい。" ) );
            }
        }

        private void L1GM( L1PcInstance pc, String cmdName, String arg )
        {
            pc.setGm( !pc.isGm() );
            pc.sendPackets( new S_SystemMessage( "setGm = " + pc.isGm() ) );
        }

        private void L1GMRoom( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                int i = 0;
                try
                {
                    i = Convert.ToInt32( arg );
                }
                catch ( Exception e )
                {
                    _log.log( Level.SEVERE, e.StackTrace );
                }

                if ( i == 1 )
                {
                    L1Teleport.teleport( pc, 32737, 32796, (short)99, 5, false );
                }
                else if ( i == 2 )
                {
                    L1Teleport.teleport( pc, 32734, 32799, (short)17100, 5, false ); // 17100!?
                }
                else if ( i == 3 )
                {
                    L1Teleport.teleport( pc, 32644, 32955, (short)0, 5, false );
                }
                else if ( i == 4 )
                {
                    L1Teleport.teleport( pc, 33429, 32814, (short)4, 5, false );
                }
                else if ( i == 5 )
                {
                    L1Teleport.teleport( pc, 32894, 32535, (short)300, 5, false );
                }
                else
                {
                    L1Location loc = GMCommandsConfig.ROOMS[arg.ToLower()];
                    if ( loc == null )
                    {
                        pc.sendPackets( new S_SystemMessage( arg + " 未定義のRoomです" ) );
                        return;
                    }
                    L1Teleport.teleport( pc, loc.getX(), loc.getY(), (short)loc.getMapId(), 5, false );
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( ".gmroom1～.gmroom5 or .gmroom name と入力して下さい。" ) );
            }
        }

        private void L1HomeTown( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer st = new StringTokenizer( arg );
                String para1 = st.nextToken();
                if ( string.Compare( para1, "daily", true ) == 0 )
                {
                    HomeTownTimeController.getInstance().dailyProc();
                }
                else if ( string.Compare( para1, "monthly", true ) == 0 )
                {
                    HomeTownTimeController.getInstance().monthlyProc();
                }
                else
                {
                    throw new Exception();
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( ".hometown daily|monthly と入力して下さい。" ) );
            }
        }

        private void L1HpBar( L1PcInstance pc, String cmdName, String arg )
        {
            if ( string.Compare( arg, "on", true ) == 0 )
            {
                pc.setSkillEffect( L1SkillId.GMSTATUS_HPBAR, 0 );
            }
            else if ( string.Compare( arg, "off", true ) == 0 )
            {
                pc.removeSkillEffect( L1SkillId.GMSTATUS_HPBAR );

                foreach ( L1Object obj in pc.getKnownObjects() )
                {
                    bool check = false;
                    if ( obj is L1MonsterInstance )
                    {
                        check = true;
                    }
                    if ( obj is L1PcInstance )
                    {
                        check = true;
                    }
                    if ( obj is L1SummonInstance )
                    {
                        check = true;
                    }
                    if ( obj is L1PetInstance )
                    {
                        check = true;
                    }
                    if ( check )
                    {
                        pc.sendPackets( new S_HPMeter( obj.getId(), 0xFF ) );
                    }
                }
            }
            else
            {
                pc.sendPackets( new S_SystemMessage( cmdName + " on|off と入力してください。" ) );
            }
        }

        private void L1InsertSpawn( L1PcInstance pc, String cmdName, String arg )
        {
            String msg = null;

            try
            {
                StringTokenizer tok = new StringTokenizer( arg );
                String type = tok.nextToken();
                int npcId = Convert.ToInt32( tok.nextToken().Trim() );
                L1Npc template = NpcTable.getInstance().getTemplate( npcId );

                if ( template == null )
                {
                    msg = "該当するNPCが見つかりません。";
                    return;
                }
                if ( type.Equals( "mob" ) )
                {
                    if ( !template.getImpl().Equals( "L1Monster" ) )
                    {
                        msg = "指定したNPCはL1Monsterではありません。";
                        return;
                    }
                    SpawnTable.storeSpawn( pc, template );
                }
                else if ( type.Equals( "npc" ) )
                {
                    NpcSpawnTable.getInstance().storeSpawn( pc, template );
                }
                L1SpawnUtil.spawn( pc, npcId, 0, 0 );
                msg = new StringBuilder().Append( template.get_name() ).Append(
                        " (" + npcId + ") " ).Append( "を追加しました。" ).ToString();
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                msg = cmdName + " mob|npc NPCID と入力して下さい。";
            }
            finally
            {
                if ( msg != null )
                {
                    pc.sendPackets( new S_SystemMessage( msg ) );
                }
            }
        }

        private void L1InvGfxId( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer st = new StringTokenizer( arg );
                int gfxid = Convert.ToInt32( st.nextToken() );
                int count = Convert.ToInt32( st.nextToken() );
                for ( int i = 0; i < count; i++ )
                {
                    L1ItemInstance item = ItemTable.getInstance().createItem( 40005 );
                    item.getItem().setGfxId( gfxid + i );
                    item.getItem().setName( Convert.ToString( gfxid + i ) );
                    pc.getInventory().storeItem( item );
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " id 出現させる数 と入力して下さい。" ) );
            }
        }

        private void L1Invisible( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                pc.setGmInvis( true );
                pc.sendPackets( new S_Invis( pc.getId(), 1 ) );
                pc.broadcastPacket( new S_RemoveObject( pc ) );
                pc.sendPackets( new S_SystemMessage( "透明状態になりました。" ) );
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " コマンドエラー" ) );
            }
        }

        private void L1Kick( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                L1PcInstance target = L1World.getInstance().getPlayer( arg );

                if ( target != null )
                {
                    pc.sendPackets( new S_SystemMessage( ( new StringBuilder() )
                            .Append( target.getName() ).Append( "さんをキックしました。" )
                            .ToString() ) );
                    target.sendPackets( new S_Disconnect() );
                }
                else
                {
                    pc.sendPackets( new S_SystemMessage(
                            "そのような名前のキャラクターはワールド内には存在しません。" ) );
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " キャラクター名 と入力して下さい。" ) );
            }
        }

        private void L1Kill( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                L1PcInstance target = L1World.getInstance().getPlayer( arg );

                if ( target != null )
                {
                    target.setCurrentHp( 0 );
                    target.death( null );
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " キャラクター名 と入力して下さい。" ) );
            }
        }

        private void L1Level( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer tok = new StringTokenizer( arg );
                int level = Convert.ToInt32( tok.nextToken() );
                if ( level == pc.getLevel() )
                {
                    return;
                }
                if ( !IntRange.includes( level, 1, 99 ) )
                {
                    pc.sendPackets( new S_SystemMessage( "1-99の範囲で指定してください" ) );
                    return;
                }
                pc.setExp( ExpTable.getExpByLevel( level ) );
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + "lv と入力して下さい" ) );
            }
        }

        private void L1LevelPresent( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer tok = new StringTokenizer( arg );
                int minlvl = Convert.ToInt32( tok.nextToken() );
                int maxlvl = Convert.ToInt32( tok.nextToken() );
                int itemid = Convert.ToInt32( tok.nextToken() );
                int enchant = Convert.ToInt32( tok.nextToken() );
                int count = Convert.ToInt32( tok.nextToken() );

                L1Item temp = ItemTable.getInstance().getTemplate( itemid );
                if ( temp == null )
                {
                    pc.sendPackets( new S_SystemMessage( "存在しないアイテムIDです。" ) );
                    return;
                }

                L1DwarfInventory.present( minlvl, maxlvl, itemid, enchant, count );
                pc.sendPackets( new S_SystemMessage( temp.getName() + "を" + count
                        + "個プレゼントしました。(Lv" + minlvl + "～" + maxlvl + ")" ) );
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( ".lvpresent minlvl maxlvl アイテムID エンチャント数 アイテム数 と入力してください。" ) );
            }
        }

        private void L1Loc( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                int locx = pc.getX();
                int locy = pc.getY();
                short mapid = pc.getMapId();
                int gab = L1WorldMap.getInstance().getMap( mapid ).getOriginalTile( locx, locy );
                String msg = String.Format( "座標 ({0}, {1}, {2}) {3}", locx, locy, mapid, gab );
                pc.sendPackets( new S_SystemMessage( msg ) );
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
            }
        }

        private void L1Move( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer st = new StringTokenizer( arg );
                int locx = Convert.ToInt32( st.nextToken() );
                int locy = Convert.ToInt32( st.nextToken() );
                short mapid;
                if ( st.hasMoreTokens() )
                {
                    mapid = Convert.ToInt16( st.nextToken() );
                }
                else
                {
                    mapid = pc.getMapId();
                }
                L1Teleport.teleport( pc, locx, locy, mapid, 5, false );
                pc.sendPackets( new S_SystemMessage( "座標 " + locx + ", " + locy
                        + ", " + mapid + "に移動しました。" ) );
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName
                        + " X座標 Y座標 [マップID] と入力して下さい。" ) );
            }
        }

        private void L1PartyRecall( L1PcInstance pc, String cmdName, String arg )
        {
            L1PcInstance target = L1World.getInstance().getPlayer( arg );

            if ( target != null )
            {
                L1Party party = target.getParty();
                if ( party != null )
                {
                    int x = pc.getX();
                    int y = pc.getY() + 2;
                    short map = pc.getMapId();
                    L1PcInstance[] players = party.getMembers();
                    foreach ( L1PcInstance pc2 in players )
                    {
                        try
                        {
                            L1Teleport.teleport( pc2, x, y, map, 5, true );
                            pc2.sendPackets( new S_SystemMessage( "ゲームマスターに召還されました。" ) );
                        }
                        catch ( Exception e )
                        {
                            _log.log( Level.SEVERE, e.StackTrace );
                        }
                    }
                }
                else
                {
                    pc.sendPackets( new S_SystemMessage( "パーティメンバーではありません。" ) );
                }
            }
            else
            {
                pc.sendPackets( new S_SystemMessage( "そのようなキャラクターはいません。" ) );
            }
        }

        private void L1Patrol( L1PcInstance pc, String cmdName, String arg )
        {
            pc.sendPackets( new S_PacketBox( S_PacketBox.CALL_SOMETHING ) );
        }

        private void L1Poly( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer st = new StringTokenizer( arg );
                String name = st.nextToken();
                int polyid = Convert.ToInt32( st.nextToken() );

                L1PcInstance tg = L1World.getInstance().getPlayer( name );

                if ( tg == null )
                {
                    pc.sendPackets( new S_ServerMessage( 73, name ) ); // \f1%0はゲームをしていません。
                }
                else
                {
                    try
                    {
                        L1PolyMorph.doPoly( tg, polyid, 7200,
                                L1PolyMorph.MORPH_BY_GM );
                    }
                    catch ( Exception e )
                    {
                        _log.log( Level.SEVERE, e.StackTrace );
                        pc.sendPackets( new S_SystemMessage( ".poly キャラクター名 グラフィックID と入力して下さい。" ) );
                    }
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " キャラクター名 グラフィックID と入力して下さい。" ) );
            }
        }

        private void L1PowerKick( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                L1PcInstance target = L1World.getInstance().getPlayer( arg );

                IpTable iptable = IpTable.getInstance();
                if ( target != null )
                {
                    iptable.banIp( target.getNetConnection().getIp() ); // BANリストへIPを加える
                    pc.sendPackets( new S_SystemMessage( ( new StringBuilder() )
                            .Append( target.getName() ).Append( "さんをキックしました。" )
                            .ToString() ) );
                    target.sendPackets( new S_Disconnect() );
                }
                else
                {
                    pc.sendPackets( new S_SystemMessage(
                            "そのような名前のキャラクターはワールド内には存在しません。" ) );
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " キャラクター名 と入力して下さい。" ) );
            }
        }

        private void L1Present( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                StringTokenizer st = new StringTokenizer( arg );
                String account = st.nextToken();
                int itemid = Convert.ToInt32( st.nextToken() );
                int enchant = Convert.ToInt32( st.nextToken() );
                int count = Convert.ToInt32( st.nextToken() );

                L1Item temp = ItemTable.getInstance().getTemplate( itemid );
                if ( temp == null )
                {
                    pc.sendPackets( new S_SystemMessage( "存在しないアイテムIDです。" ) );
                    return;
                }

                L1DwarfInventory.present( account, itemid, enchant, count );
                pc.sendPackets( new S_SystemMessage( temp.getIdentifiedNameId()
                        + "を" + count + "個プレゼントしました。", true ) );
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage(
                                ".present アカウント名 アイテムID エンチャント数 アイテム数 と入力してください。（アカウント名=*で全て）" ) );
            }
        }

        private void L1Recall( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                List<L1PcInstance> targets = null;
                if ( string.Compare( arg, "all", true ) == 0 )
                {
                    foreach ( L1PcInstance lpi in L1World.getInstance().getAllPlayers() )
                    {
                        targets.Add( lpi );
                    }
                }
                else
                {
                    targets = new List<L1PcInstance>();
                    L1PcInstance tg = L1World.getInstance().getPlayer( arg );
                    if ( tg == null )
                    {
                        pc.sendPackets( new S_SystemMessage( "そのようなキャラクターはいません。" ) );
                        return;
                    }
                    targets.Add( tg );
                }

                foreach ( L1PcInstance target in targets )
                {
                    if ( target.isGm() )
                    {
                        continue;
                    }
                    L1Teleport.teleportToTargetFront( target, pc, 2 );
                    pc.sendPackets( new S_SystemMessage( ( new StringBuilder() )
                            .Append( target.getName() ).Append( "さんを召還しました。" )
                            .ToString() ) );
                    target.sendPackets( new S_SystemMessage( "ゲームマスターに召還されました。" ) );
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName
                        + " all|キャラクター名 と入力して下さい。" ) );
            }
        }

        private void L1ReloadTrap( L1PcInstance pc, String cmdName, String arg )
        {
            L1WorldTraps.reloadTraps();
            pc.sendPackets( new S_SystemMessage( "トラップを再読み込みしました" ) );
        }

        private void L1ResetTrap( L1PcInstance pc, String cmdName, String arg )
        {
            L1WorldTraps.getInstance().resetAllTraps();
            pc.sendPackets( new S_SystemMessage( "トラップを再配置しました" ) );
        }
        private void L1Ress( L1PcInstance pc, String cmdName, String arg )
        {
            try
            {
                int objid = pc.getId();
                pc.sendPackets( new S_SkillSound( objid, 759 ) );
                pc.broadcastPacket( new S_SkillSound( objid, 759 ) );
                pc.setCurrentHp( pc.getMaxHp() );
                pc.setCurrentMp( pc.getMaxMp() );
                foreach ( L1PcInstance tg in L1World.getInstance().getVisiblePlayer( pc ) )
                {
                    if ( tg.getCurrentHp() == 0 && tg.isDead() )
                    {
                        tg.sendPackets( new S_SystemMessage( "GMに蘇生を貰いました。" ) );
                        tg.broadcastPacket( new S_SkillSound( tg.getId(), 3944 ) );
                        tg.sendPackets( new S_SkillSound( tg.getId(), 3944 ) );
                        // 祝福された 復活スクロールと同じ効果
                        tg.setTempID( objid );
                        tg.sendPackets( new S_Message_YN( 322, "" ) ); // また復活したいですか？（Y/N）
                    }
                    else
                    {
                        tg.sendPackets( new S_SystemMessage( "GMが癒してくれました。" ) );
                        tg.broadcastPacket( new S_SkillSound( tg.getId(), 832 ) );
                        tg.sendPackets( new S_SkillSound( tg.getId(), 832 ) );
                        tg.setCurrentHp( tg.getMaxHp() );
                        tg.setCurrentMp( tg.getMaxMp() );
                    }
                }
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                pc.sendPackets( new S_SystemMessage( cmdName + " コマンドエラー" ) );
            }
        }

        private void L1ShowTrap( L1PcInstance pc, String cmdName, String arg )
        {
            if ( string.Compare( arg, "on", true ) == 0 )
            {
                pc.setSkillEffect( L1SkillId.GMSTATUS_SHOWTRAPS, 0 );
            }
            else if ( string.Compare( arg, "off", true ) == 0 )
            {
                pc.removeSkillEffect( L1SkillId.GMSTATUS_SHOWTRAPS );

                foreach ( L1Object obj in pc.getKnownObjects() )
                {
                    if ( obj is L1TrapInstance )
                    {
                        pc.removeKnownObject( obj );
                        pc.sendPackets( new S_RemoveObject( obj ) );
                    }
                }
            }
            else
            {
                pc.sendPackets( new S_SystemMessage( cmdName + " on|off と入力してください。" ) );
            }
        }

        private void L1Shutdown( L1PcInstance pc, String cmdName, String arg )
        {
            if ( string.Compare( arg, "now", true ) == 0 )
            {
                GameServer.getInstance().shutdown();
                return;
            }
            if ( string.Compare( arg, "abort", true ) == 0 )
            {
                GameServer.getInstance().abortShutdown();
                return;
            }
            int sec = Math.Max( 5, Convert.ToInt32( arg ) );
            GameServer.getInstance().shutdownWithCountdown( sec );
        }

        private void L1SKick( L1PcInstance pc, String cmdName, String arg )
        {
            L1PcInstance target = L1World.getInstance().getPlayer( arg );
            if ( target != null )
            {
                pc.sendPackets( new S_SystemMessage( ( new StringBuilder() )
                        .Append( target.getName() ).Append( "さんをキックしました。" )
                        .ToString() ) );
                // SKTへ移動させる
                target.setX( 33080 );
                target.setY( 33392 );
                target.setMap( (short)4 );
                target.sendPackets( new S_Disconnect() );
                ClientThread targetClient = target.getNetConnection();
                targetClient.kick();
                _log.warning( "GMのskickコマンドにより(" + targetClient.getAccountName()
                        + ":" + targetClient.getHostname() + ")との接続を強制切断しました。" );
            }
            else
            {
                pc.sendPackets( new S_SystemMessage(
                        "そのような名前のキャラクターはワールド内には存在しません。" ) );
            }
        }

        private void L1SpawnCmd( L1PcInstance pc, String cmdName, String arg )
        {
            StringTokenizer tok = new StringTokenizer( arg );
            String nameId = tok.nextToken();
            int count = 1;
            if ( tok.hasMoreTokens() )
            {
                count = Convert.ToInt32( tok.nextToken() );
            }
            int randomrange = 0;
            if ( tok.hasMoreTokens() )
            {
                randomrange = Convert.ToInt32( tok.nextToken() );
            }
            int npcid = 0;
            try
            {
                npcid = Convert.ToInt32( nameId );
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                npcid = NpcTable.getInstance().findNpcIdByNameWithoutSpace( nameId );
            }

            L1Npc npc = NpcTable.getInstance().getTemplate( npcid );
            if ( npc == null )
            {
                pc.sendPackets( new S_SystemMessage( "該当NPCが見つかりません。" ) );
                return;
            }
            for ( int i = 0; i < count; i++ )
            {
                L1SpawnUtil.spawn( pc, npcid, randomrange, 0 );
            }
            String msg = String.Format( "{0}({1}) ({2}) を召還しました。 (範囲:%d)", npc
                    .get_name(), npcid, count, randomrange );
            pc.sendPackets( new S_SystemMessage( msg ) );
        }

        private void L1Speed( L1PcInstance pc, String cmdName, String arg )
        {
            L1BuffUtil.haste( pc, 3600 * 1000 );
            L1BuffUtil.brave( pc, 3600 * 1000 );
        }

        private void L1Status( L1PcInstance pc, String cmdName, String arg )
        {
            StringTokenizer st = new StringTokenizer( arg );
            String char_name = st.nextToken();
            String param = st.nextToken();
            int value = Convert.ToInt32( st.nextToken() );

            L1PcInstance target = null;
            if ( string.Compare( char_name, "me", true ) == 0 )
            {
                target = pc;
            }
            else
            {
                target = L1World.getInstance().getPlayer( char_name );
            }

            if ( target == null )
            {
                pc.sendPackets( new S_ServerMessage( 73, char_name ) ); // \f1%0はゲームをしていません。
                return;
            }

            // -- not use DB --
            if ( string.Compare( param, "AC", true ) == 0 )
            {
                target.addAc( (byte)( value - target.getAc() ) );
            }
            else if ( string.Compare( param, "MR", true ) == 0 )
            {
                target.addMr( (short)( value - target.getMr() ) );
            }
            else if ( string.Compare( param, "HIT", true ) == 0 )
            {
                target.addHitup( (short)( value - target.getHitup() ) );
            }
            else if ( string.Compare( param, "DMG", true ) == 0 )
            {
                target.addDmgup( (short)( value - target.getDmgup() ) );
                // -- use DB --
            }
            else
            {
                if ( string.Compare( param, "HP", true ) == 0 )
                {
                    target
                            .addBaseMaxHp( (short)( value - target
                                    .getBaseMaxHp() ) );
                    target.setCurrentHpDirect( target.getMaxHp() );
                }
                else if ( string.Compare( param, "MP", true ) == 0 )
                {
                    target
                            .addBaseMaxMp( (short)( value - target
                                    .getBaseMaxMp() ) );
                    target.setCurrentMpDirect( target.getMaxMp() );
                }
                else if ( string.Compare( param, "LAWFUL", true ) == 0 )
                {
                    target.setLawful( value );
                    S_Lawful s_lawful = new S_Lawful( target.getId(), target
                            .getLawful() );
                    target.sendPackets( s_lawful );
                    target.broadcastPacket( s_lawful );
                }
                else if ( string.Compare( param, "KARMA", true ) == 0 )
                {
                    target.setKarma( value );
                }
                else if ( string.Compare( param, "GM", true ) == 0 )
                {
                    if ( value > 200 )
                    {
                        value = 200;
                    }
                    target.setAccessLevel( (short)value );
                    target.sendPackets( new S_SystemMessage(
                            "リスタートすれば、GMに昇格されています。" ) );
                }
                else if ( string.Compare( param, "STR", true ) == 0 )
                {
                    target.addBaseStr( (byte)( value - target.getBaseStr() ) );
                }
                else if ( string.Compare( param, "CON", true ) == 0 )
                {
                    target.addBaseCon( (byte)( value - target.getBaseCon() ) );
                }
                else if ( string.Compare( param, "DEX", true ) == 0 )
                {
                    target.addBaseDex( (byte)( value - target.getBaseDex() ) );
                }
                else if ( string.Compare( param, "INT", true ) == 0 )
                {
                    target.addBaseInt( (byte)( value - target.getBaseInt() ) );
                }
                else if ( string.Compare( param, "WIS", true ) == 0 )
                {
                    target.addBaseWis( (byte)( value - target.getBaseWis() ) );
                }
                else if ( string.Compare( param, "CHA", true ) == 0 )
                {
                    target.addBaseCha( (byte)( value - target.getBaseCha() ) );
                }
                else
                {
                    pc.sendPackets( new S_SystemMessage( "ステータス " + param
                            + " は不明です。" ) );
                    return;
                }
                target.save(); // DBにキャラクター情報を書き込む
            }
            target.sendPackets( new S_OwnCharStatus( target ) );
            pc.sendPackets( new S_SystemMessage( target.getName() + " の" + param
                    + "を" + value + "に変更しました。" ) );
        }

        private void L1Summon( L1PcInstance pc, String cmdName, String arg )
        {
            StringTokenizer tok = new StringTokenizer( arg );
            String nameid = tok.nextToken();
            int npcid = 0;
            try
            {
                npcid = Convert.ToInt32( nameid );
            }
            catch ( Exception e )
            {
                _log.log( Level.SEVERE, e.StackTrace );
                npcid = NpcTable.getInstance().findNpcIdByNameWithoutSpace( nameid );
                if ( npcid == 0 )
                {
                    pc.sendPackets( new S_SystemMessage( "該当NPCが見つかりません。" ) );
                    return;
                }
            }
            int count = 1;
            if ( tok.hasMoreTokens() )
            {
                count = Convert.ToInt32( tok.nextToken() );
            }
            L1Npc npc = NpcTable.getInstance().getTemplate( npcid );
            for ( int i = 0; i < count; i++ )
            {
                L1SummonInstance summonInst = new L1SummonInstance( npc, pc );
                summonInst.setPetcost( 0 );
            }
            nameid = NpcTable.getInstance().getTemplate( npcid ).get_name();
            pc.sendPackets( new S_SystemMessage( nameid + "(ID:" + npcid + ") ("
                    + count + ") を召還しました。" ) );
        }

        private void L1Tile( L1PcInstance pc, String cmdName, String arg )
        {
            int locX = pc.getX();
            int locY = pc.getY();
            short mapId = pc.getMapId();
            int tile0 = L1WorldMap.getInstance().getMap( mapId ).getOriginalTile( locX, locY - 1 );
            int tile1 = L1WorldMap.getInstance().getMap( mapId ).getOriginalTile( locX + 1, locY - 1 );
            int tile2 = L1WorldMap.getInstance().getMap( mapId ).getOriginalTile( locX + 1, locY );
            int tile3 = L1WorldMap.getInstance().getMap( mapId ).getOriginalTile( locX + 1, locY + 1 );
            int tile4 = L1WorldMap.getInstance().getMap( mapId ).getOriginalTile( locX, locY + 1 );
            int tile5 = L1WorldMap.getInstance().getMap( mapId ).getOriginalTile( locX - 1, locY + 1 );
            int tile6 = L1WorldMap.getInstance().getMap( mapId ).getOriginalTile( locX - 1, locY );
            int tile7 = L1WorldMap.getInstance().getMap( mapId ).getOriginalTile( locX - 1, locY - 1 );
            String msg = String.Format( "0:{0} 1:{1} 2:{2} 3:{3} 4:{4} 5:{5} 6:{6} 7:{7}",
                    tile0, tile1, tile2, tile3, tile4, tile5, tile6, tile7 );
            pc.sendPackets( new S_SystemMessage( msg ) );
        }

        private void L1ToPC( L1PcInstance pc, String cmdName, String arg )
        {
            L1PcInstance target = L1World.getInstance().getPlayer( arg );

            if ( target != null )
            {
                L1Teleport.teleport( pc, target.getX(), target.getY(), target.getMapId(), 5, false );
                pc.sendPackets( new S_SystemMessage( ( new StringBuilder() )
                        .Append( arg ).Append( "さんの元へ移動しました。" ).ToString() ) );
            }
            else
            {
                pc.sendPackets( new S_SystemMessage( ( new StringBuilder() )
                        .Append( arg ).Append( "さんはいません。" ).ToString() ) );
            }
        }

        private static Dictionary<int, int> _spawnId = new Dictionary<int, int>();
        private void L1ToSpawn( L1PcInstance pc, String cmdName, String arg )
        {
            if ( !_spawnId.ContainsKey( pc.getId() ) )
            {
                _spawnId.Add( pc.getId(), 0 );
            }
            int id = _spawnId[pc.getId()];
            if ( arg.Length == 0 || arg.Equals( "+" ) )
            {
                id++;
            }
            else if ( arg.Equals( "-" ) )
            {
                id--;
            }
            else
            {
                StringTokenizer st = new StringTokenizer( arg );
                id = Convert.ToInt32( st.nextToken() );
            }
            L1Spawn spawn = NpcSpawnTable.getInstance().getTemplate( id );
            if ( spawn == null )
            {
                spawn = SpawnTable.getInstance().getTemplate( id );
            }
            if ( spawn != null )
            {
                L1Teleport.teleport( pc, spawn.getLocX(), spawn.getLocY(), spawn.getMapId(), 5, false );
                pc.sendPackets( new S_SystemMessage( "spawnid(" + id + ")の元へ飛びます" ) );
            }
            else
            {
                pc.sendPackets( new S_SystemMessage( "spawnid(" + id + ")は見つかりません" ) );
            }
            _spawnId.Add( pc.getId(), id );
        }

        private void L1Visible( L1PcInstance pc, String cmdName, String arg )
        {
            pc.setGmInvis( false );
            pc.sendPackets( new S_Invis( pc.getId(), 0 ) );
            pc.broadcastPacket( new S_OtherCharPacks( pc ) );
            pc.sendPackets( new S_SystemMessage( "透明状態を解除しました。" ) );
        }

        private void L1Who( L1PcInstance pc, String cmdName, String arg )
        {
            ICollection players = L1World.getInstance().getAllPlayers();
            String amount = players.Count.ToString();
            S_WhoAmount s_whoamount = new S_WhoAmount( amount );
            pc.sendPackets( s_whoamount );

            // オンラインのプレイヤーリストを表示
            if ( string.Compare( arg, "all" ,true) == 0 )
            {
                pc.sendPackets( new S_SystemMessage( "-- オンラインのプレイヤー --" ) );
                StringBuilder buf = new StringBuilder();
                foreach ( L1PcInstance each in players )
                {
                    buf.Append( each.getName() );
                    buf.Append( " / " );
                    if ( buf.Length > 50 )
                    {
                        pc.sendPackets( new S_SystemMessage( buf.ToString() ) );
                        buf.Remove( 0, buf.Length - 1 );
                    }
                }
                if ( buf.Length > 0 )
                {
                    pc.sendPackets( new S_SystemMessage( buf.ToString() ) );
                }
            }
        }

        private void L1Echo( L1PcInstance pc, String cmdName, String arg )
        {
            pc.sendPackets( new S_SystemMessage( arg ) );
        }
    }
}
